<?php
/**
 *
 *
 *
 */
class Yz_Form_Element_Input
    extends Yz_Form_Element_Abstract
{
    protected $element;
    protected $property;
    /** the element's form field value
     *  NOTE required in case the input value (eg from POST) could not be assigned and
     *      needs to be displayed as incorrect input
     *  @var string
     */
    protected $value = "";
    protected $isParseable = true;

    /**
     *  @param Yz_Form_Interface the form the element belongs to
     *  @param string name
     *  @param Yz_Property_Interface $element
     */
    public function __construct(
        Yz_Form_Interface $form,
        $name,
        Yz_Property_Interface $element
        )
    {
        debug();
        assert('is_string($name) and "" !== $name');
        $this->name = $name;
        $this->property = $element;
        $this->element =& $this->property;
        $this->form = $form;
        return;
    }


    /**
     *
     */
    public function render(Yz_Template_Interface $template)
    {
        $o = <<<html
            <input type="text" name="{$this->name}" value="{$this->value}" />\n
html;
        return $o;
    }


    /** 'parse' form-data array values to obtain correct value
     *      return boolean, whether the value is to be assigned
     *  @param Yz_Hash $values
     *  @return mixed
     *  @throw Yz_Form_Element_Error
     */
    public function parse(Yz_Hash $input)
    {
        debug("$this");
        $val =& $this->value;
        $val = null; // discard old value
        try {
            $val = $this->validateType($input[$this->name]);
            $val = $this->validateValue($val);
        } catch (Yz_Form_Element_Error $ex) {
            $this->error = $ex;
            throw $ex;
        }
        return $val;
    }


    /**
     *  @return bool
     */
    public function allowEmpty()
    {
        debug();
        return !$this->property->notnull();
    }


    /********************************
     *        Protected methods     *
     *******************************/


    /** Validate an input value, returning a value which is of correct type to assign to item
     *      NOTE: For a GET/POST parameter, the only possible value types are string or array
     *  @param  string|array|null
     *  @return string|null
     *  @throw Yz_Form_Error_InvalidFormError
     */
    protected function validateType($input)
    {
        debug();
        if (null === $input or ! is_string($input))
            // missing value or array indicates incorrect form
            // this error is not caught in parse()
            throw Yz_Form_Error_InvalidFormError::_new_();
        $value = trim($input);
        if ("" === $value)
            $value = null;
        // returned value will be assigned to $this.value
        return $value;
    }

    /** Validate an input value, returning a value which is of correct type to assign to item
     *      NOTE: For a GET/POST parameter, the only possible value types are string or array
     *  @param  string|array|null
     *  @return string|null
     *  @throw Yz_Form_Element_Error_ValueError
     */
    protected function validateValue($value)
    {
        debug();
        try {
            // TODO which exactly constraint failed ?
            $value = $this->property->testValue($value);
        } catch (ValueError $ex) {
            throw Yz_Form_Element_Error_ValueError::_new_(null, $ex);
        }
        // other error types mean that something is programmatically wrong
        // returned value will be assigned to $this.value
        return $value;
    }
}
